﻿// <copyright file="Window1.xaml.cs" company="ALCPU">
// Copyright (c) 2010 All Right Reserved
// </copyright>
// <author>Arthur Liberman</author>
// <email>Arthur_Liberman@hotmail.com</email>
// <date>03-30-2010</date>
// <summary>Window1 code.</summary>

namespace Chess
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    using Chess.Checkers;
    using Chess.Figures;
    using ChessDefinitions;

    /// <summary>
    /// Determines the game type.
    /// </summary>
    public enum GameType
    {
        /// <summary>
        /// A Chess game.
        /// </summary>
        Chess,

        /// <summary>
        /// A Checkers game.
        /// </summary>
        Checkers
    }

    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        /// <summary>
        /// The gameboard.
        /// </summary>
        private Chess.Gameboard gameboard;

        /// <summary>
        /// White player.
        /// </summary>
        private PlayerBase playerWhite;

        /// <summary>
        /// Black player.
        /// </summary>
        private PlayerBase playerBlack;

        /// <summary>
        /// Currently active player.
        /// </summary>
        private PlayerBase currentPlayer;

        /// <summary>
        /// The opponent of <paramref name="currentPlayer"/>.
        /// </summary>
        private PlayerBase opposingPlayer;

        /// <summary>
        /// Initializes a new instance of the <see cref="Window1"/> class.
        /// </summary>
        /// <param name="gameType">Type of the game.</param>
        public Window1(GameType gameType)
        {
            InitializeComponent();

            this.GameType = gameType;
            this.SetUpGameboard();
            this.gameClock.TimeoutOccured += new EventHandler(this.GameClock_TimeoutOccured);
            this.IsGameActive = false;
        }

        /// <summary>
        /// Gets or sets the type of the game.
        /// </summary>
        /// <value>The type of the game.</value>
        public GameType GameType { get; set; }

        /// <summary>
        /// Gets or sets a value indicating whether the game is active.
        /// </summary>
        /// <value>
        ///     <c>true</c> if the game is active; otherwise, <c>false</c>.
        /// </value>
        private bool IsGameActive { get; set; }

        /// <summary>
        /// Handles the MouseLeftButtonDown event of the Gameboard control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void Gameboard_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (!this.IsGameActive)
            {
                return;
            }

            this.currentPlayer.HandleUserInput(e);
        }

        /// <summary>
        /// Handles the MouseRightButtonDown event of the Gameboard control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void Gameboard_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            this.currentPlayer.HandleUserInput(e);
        }

        /// <summary>
        /// Handles the Click event of the newGameButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void NewGameButton_Click(object sender, RoutedEventArgs e)
        {
            this.StartNewGame();
        }

        /// <summary>
        /// A player's game event.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="gea">The <see cref="ChessDefinitions.GameEventArgs&lt;ChessDefinitions.PlayerBase&gt;"/> instance containing the event data.</param>
        private void Player_GameEvent(PlayerBase sender, GameEventArgs<PlayerBase> gea)
        {
            if (gea != null)
            {
                this.CheckGameEvents(gea.GameEventType);
            }
        }

        /// <summary>
        /// Handles the TimeoutOccured event of the GameClock control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void GameClock_TimeoutOccured(object sender, EventArgs e)
        {
            this.EndGame(GameEventType.Timeout);
        }

        /// <summary>
        /// Swaps the current player.
        /// </summary>
        private void SwapCurrentPlayer()
        {
            this.gameClock.TogglePlayer();
            if (this.currentPlayer == this.playerWhite)
            {
                this.currentPlayer = this.playerBlack;
                this.opposingPlayer = this.playerWhite;
            }
            else if (this.currentPlayer == this.playerBlack)
            {
                this.currentPlayer = this.playerWhite;
                this.opposingPlayer = this.playerBlack;
            }

            this.currentPlayer.StartTurn();
        }

        /// <summary>
        /// Checks the game events.
        /// </summary>
        /// <param name="gameEvent">The game event.</param>
        private void CheckGameEvents(GameEventType gameEvent)
        {
            if (gameEvent != GameEventType.None)
            {
                switch (gameEvent)
                {
                    case GameEventType.Check:
                        MessageBox.Show("Check");
                        break;
                    case GameEventType.Checkmate:
                        this.EndGame(gameEvent);
                        MessageBox.Show("Checkmate");
                        break;
                    case GameEventType.Stalemate:
                        this.EndGame(gameEvent);
                        MessageBox.Show("Stalemate");
                        break;
                    case GameEventType.NoLegalMoves:
                        this.EndGame(gameEvent);
                        MessageBox.Show("No legal moves remain");
                        break;
                    case GameEventType.TurnEnded:
                        this.SwapCurrentPlayer();
                        break;
                    case GameEventType.Attack:
                    case GameEventType.Move:
                        this.gameClock.MoveCount++;
                        GameEventType moveEvent = this.currentPlayer.CheckEndgame(this.opposingPlayer);
                        if (moveEvent != GameEventType.None)
                        {
                            this.CheckGameEvents(moveEvent);
                        }

                        break;
                }
            }
        }

        /// <summary>
        /// Ends the game.
        /// </summary>
        /// <param name="gameEventType">Type of the game event.</param>
        private void EndGame(GameEventType gameEventType)
        {
            this.IsGameActive = false;
            if (gameEventType != GameEventType.Timeout)
            {
                // Swap back to the last player who made the move.
                this.SwapCurrentPlayer();
                this.gameClock.StopClock();
            }

            this.gameboard.RecolorGameboard();
            MessageBox.Show("Game over");
        }

        /// <summary>
        /// Starts a new game.
        /// </summary>
        private void StartNewGame()
        {
            this.IsGameActive = true;
            this.SetUpGameboard();
            this.gameClock.StartClock();
            this.currentPlayer.StartTurn();
        }

        /// <summary>
        /// Sets up the gameboard.
        /// </summary>
        private void SetUpGameboard()
        {
            this.gameboard = new Gameboard(Gameboard);
            if (this.GameType == GameType.Checkers)
            {
                this.playerBlack = this.opposingPlayer = new PlayerCheckers(IPieceColor.Black, this.gameboard);
                this.playerWhite = this.currentPlayer = new PlayerCheckers(IPieceColor.White, this.gameboard);
            }
            else
            {
                this.playerBlack = this.opposingPlayer = new PlayerChess(IPieceColor.Black, this.gameboard);
                this.playerWhite = this.currentPlayer = new PlayerChess(IPieceColor.White, this.gameboard);
            }

            this.playerWhite.GameEvent += new PlayerEvent(this.Player_GameEvent);
            this.playerBlack.GameEvent += new PlayerEvent(this.Player_GameEvent);

            this.gameClock.StopClock();
            this.gameClock.ClockMode = ClockMode.Timer;
            this.gameClock.SetTimeLimit(TimeSpan.FromMinutes(10));
            this.gameClock.ResetClock();
        }
    }
}
